//SSAOData.h
//Created 19/01/14
//Created By Daniel Bowler
//
//This class contains all the data (eg textures) that we need to support
//SSAO in a game. Note, this is for a forward renderer and not a deferred
//system. 

#pragma once

//For XNA/D3D headers
#include "d3dUtil.h"

//Forward declare effects that we use
class SSAOMapFX;
class SSAOBlurFX;
class SSAOBlurCSFX;

//Forward declare virtual camera
class VirtualCamera;

class SSAOData
{
public:
	//Constructor - pass in the render target (backbuffer) height/width. We will
	//create a screen sized normal/depth texture. 
	SSAOData(ID3D11Device* device, unsigned height, unsigned width, 
		ID3D11Buffer* quadVB, ID3D11Buffer* quadIB);
	~SSAOData();

	//Called when the screen resizes or MSAA state changes .We will have to resize 
	//our view space normals/depths texture (amongst others) 
	void Rebuild(ID3D11Device* device, unsigned newHeight, unsigned newWidth);

public:
	//Once we have the view space normals and depths (after the Zpre pass stage), we
	//need to feed these textures in to a seperate effect to generate an SSAOMap.
	void GenerateSSAOMap(ID3D11DeviceContext* context, VirtualCamera* camera);
	//The final stage is to blur the SSAO Map since we only take a few samples. This
	//significantly imrpvoes the SSAO Map for use use in lighting.
	void BlurSSAOMap(ID3D11DeviceContext* context, unsigned blurCount);
	//Alternativly, blur with Compute Shader
	void BlurSSAOMapCS(ID3D11DeviceContext* context, unsigned blurCount);

public:
	//Returns the viewNormalDepth Render Target View to bind in the ZPrePass
	//stage
	ID3D11RenderTargetView* ReturnViewNormalDepthRTV() {return viewNormalDepthRTV;};
	ID3D11ShaderResourceView* ReturnViewNormalDepthSRV() {return viewNormalDepthSRV;};
	//returns the SSAO Map post blur
	ID3D11ShaderResourceView* ReturnSSAOMap(){return ssaoMapSRV;};

private:
	//Private function that is called in the constructor and OnResize function that
	//generates all of the data we require for this effect. 
	void CreateViews(ID3D11Device* device);

	//Creates normal depth views (Pass one)
	void CreateNormalDepthViews(ID3D11Device* device);
	//Creates SSAO Map texture (Pass two)
	void CreateSSAOMapTexture(ID3D11Device* device);
	//Creates second SSAOMap texture for pass 3.
	void CreateSecondSSAOMapTexture(ID3D11Device* device);

	//Create quads
	void CreateSSAOQuad(ID3D11Device* device);

	//Builds offset vectors and random vectors for use in pass two.
	void CreateOffsetVectors();
	void CreateRandomVectorTexture(ID3D11Device* device);
	//Builds frustum corners which we will use in pass two.
	void BuildFrustumCorners(float fovY, float farZ);

private:
	//Carries out the blur
	void Blur(ID3D11DeviceContext* context,
		ID3D11ShaderResourceView* input, ID3D11RenderTargetView* output, bool horizontal);
	//Used when CS is requested
	void BlurCS(ID3D11DeviceContext* context,
		ID3D11ShaderResourceView* input, ID3D11UnorderedAccessView* output, bool horizontal);

private:
	//First pass: screen sized render target that we bind in the z pre pass stage. Here, 
	//we will write the view space normal of every fragment and the view
	//space depth of every fragment in the pixel shader. 
	ID3D11RenderTargetView* viewNormalDepthRTV;
	ID3D11ShaderResourceView* viewNormalDepthSRV;

private:
	//Pass 2: SSAO Map generation.
	//
	//RTV and SRV to the SSAO Map - When bluring, we will need a second
	//for ping-ponging.
	//
	//This SRV will be the useful SRV after bluring. 
	ID3D11RenderTargetView* ssaoMapRTV;
	ID3D11ShaderResourceView* ssaoMapSRV;
	ID3D11UnorderedAccessView* ssaoMapUAV;

	//Two XMFLOAT4 arrays - one for the offset vectors (obtained in the PS
	//per occlusion sample/test. We will reflect them around a random vector
	//to produce less static vectors).
	XMFLOAT4 offsetVectors[14];
	//Frustum corners, aids in rebuilding view space x,y,z coords from the depth.
	//In the VS, we will create a vector from the origin (viewspace) to the 
	//far frustum plane. 
	XMFLOAT4 frustumCorners[4];

	//FullScreen quad used when we render the SSAO generator map.
	ID3D11Buffer* ssaoMapGenVB;
	ID3D11Buffer* ssaoMapGenIB;

	//SRV to our randomly generated vectors.
	ID3D11ShaderResourceView* ssaoMapRandomVectorsSRV;
	//Viewport - The SSAO map will be 1/2 the dimentions of the render
	//target / view space normal depth RTV.
	//
	//Also used in pass three.
	D3D11_VIEWPORT ssaoMapViewport;

private:
	//Pass 3:
	//
	//We need a second ssaoMapRTV and SRV for the pingponging 
	//blur effect
	ID3D11RenderTargetView* ssaoMapRTV1;
	ID3D11ShaderResourceView* ssaoMapSRV1;
	ID3D11UnorderedAccessView* ssaoMapUAV1;

	//Full screen quad - used when we blur the SSAOMap - DO NOT RELEASE
	//AS THEY ARE PASSED FROM THE GraphicsInterface.
	ID3D11Buffer* quadVB;
	ID3D11Buffer* quadIB;

private:
	//Effects that are used to generate the SSAOMap - Phase one is handled by
	//the graphics interface whilst 2 and 3 are deleated to this class. 
	//
	//Phase 2:
	SSAOMapFX* ssaoMapFX;
	//Phase 3:
	SSAOBlurFX* ssaoBlurFX;
	SSAOBlurCSFX* ssaoBlurCSFX;

private:
	//Width/height of the render target (backbuffer)
	unsigned rtHeight;
	unsigned rtWidth;
	float fovy;
	float farz;
};